package org.jeecg.modules.demo.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.crypto.SecureUtil;
import org.jeecg.modules.demo.bean.vo.FileResourceVo;
import org.jeecg.modules.demo.exception.BusinessException;
import org.jeecg.modules.demo.service.FileManagerService;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.demo.upload.service.ZyUploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

/**
 * 本地实现的文件管理服务
 * @author : willian fu
 * @date : 2022/9/7
 */
@Slf4j
@Service
public class LocalFileManagerServiceImpl implements FileManagerService {

    @Value("${wflow.file.max-size:20}")
    private Integer maxSize;

    //默认文件存储路径
    private static final String BASE_DIR_FILE = "resource/file";
    private static final String BASE_SIGN_FILE = "resource/sign";
    //操作系统信息
    private final static String OS = System.getProperty("os.name").toLowerCase();

    @Autowired
    private ZyUploadService zyUploadService;

    @Override
    public FileResourceVo uploadFile(MultipartFile file, Boolean isImg, Boolean isSign) throws IOException {
        if (file.getSize() / 1048576 > maxSize){
            throw new BusinessException("管理员限制了最大文件大小为" + maxSize + "MB");
        }
        String name = file.getOriginalFilename();
        FileResourceVo resourceVo = null;
        InputStream inputStream = null;
        try {
            // 读取文件内容
            inputStream = file.getInputStream();
            // MD5可以将任意长度的数据映射成固定长度的唯一字符串
            // 这样可以唯一地标识文件的内容
            String md5 = SecureUtil.md5(inputStream).substring(8, 24);
            // System.out.println("SecureUtil.md5(file.getInputStream()) = " + SecureUtil.md5(file.getInputStream()));
            String type = name.substring(name.lastIndexOf("."));
            String fullPath = getPathByOs(true, isSign ? BASE_SIGN_FILE : BASE_DIR_FILE, md5) + type;
            //"/wflow/res/" + md5 + type
            String s = zyUploadService.uploadSceneFile1(file);
//            resourceVo = FileResourceVo.builder().id(md5 + type).isImage(isImg)
//                    .url(s).size(file.getSize()).name(name).build();
//
            resourceVo = FileResourceVo.builder().id(md5 + type).isImage(isImg)
                    .url(s).size(file.getSize()).name(name).build();
            if (!FileUtil.exist(fullPath)) {
                //  如果传入的文件路径为空，则返回null
                //  调用touch方法并传入通过file方法获取到的文件对象
                //  如果文件不存在，则创建该文件父目录，并创建新文件
                File touch = FileUtil.touch(fullPath);
                System.out.println("touch.length() = " + touch.length());
                log.info("云端上传文件[{} => {}]成功，url是 {}", name, md5,s);
                file.transferTo(touch);
                log.info("上传文件[{} => {}]成功", name, md5);
            } else {
                log.info("上传文件[{} => {}]成功，文件已存在", name, md5);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 垃圾回收
            System.gc();
        }
        return resourceVo;
    }

    @Override
    public void delFileById(String fileId, Boolean isSign) {
        String path = getPathByOs(true, isSign ? BASE_SIGN_FILE : BASE_DIR_FILE, fileId);
        if (FileUtil.exist(path)){
            FileUtil.del(path);
        }else {
            throw new BusinessException("文件不存在");
        }
        log.info("删除文件[{}]成功", fileId);
    }

    @Override
    public InputStreamResource getFileById(String fileId, String name, Boolean isSign) throws IOException {
        String path = getPathByOs(true, isSign ? BASE_SIGN_FILE : BASE_DIR_FILE, fileId);
        if (FileUtil.exist(path)){
          return new InputStreamResource(new FileInputStream(path));
        }else {
            throw new BusinessException("文件不存在");
        }
    }

    /**
     * @param isAb 是否相对路径
     * @param path xx.xx.xx
     * @return 对应系统下路径
     */
    public static synchronized String getPathByOs(boolean isAb, String ...path){
        StringBuilder builder = new StringBuilder(isAb ? System.getProperty("user.dir") : "");
        for (String pt : path) {
            builder.append("/").append(pt);
        }
        if (!isAb){
            builder.deleteCharAt(0);
        }
        return OS.startsWith("win") ?
                builder.toString().replaceAll("/", "\\\\")
                : builder.toString();
    }
}
